package com.sinosoft.vaccinetoai.dao.redis.mapper.impl;

import com.sinosoft.vaccinetoai.dao.redis.mapper.IRedisBaseDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Repository
public class RedisBaseDaoImpl implements IRedisBaseDao {

    //默认时间单位
    private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;

    @Autowired(required = false)
    private RedisTemplate redisTemplate;

    @Override
    public Set<String> keys(String keyPattern) throws Exception {
        return redisTemplate.keys(keyPattern);
    }

    @Override
    public boolean existsKey(String key) throws Exception {
        return (Boolean) redisTemplate.execute((RedisCallback) (connection) -> {
            return connection.exists(redisTemplate.getKeySerializer().serialize(key));
        });
    }

    @Override
    public long incrby(String key, long step) throws Exception {
        return redisTemplate.opsForValue().increment(key, step);
    }

    @Override
    public double incrby(String key, double step) throws Exception {
        return redisTemplate.opsForValue().increment(key, step);
    }

    @Override
    public long hIncrby(String key, String subKey, long step) throws Exception {
        BoundHashOperations ops = redisTemplate.boundHashOps(key);
        return ops.increment(subKey, step);
    }

    @Override
    public double hIncrby(String key, String subKey, double step) throws Exception {
        BoundHashOperations ops = redisTemplate.boundHashOps(key);
        return ops.increment(subKey, step);
    }

    @Override
    public Boolean delete(String key) throws Exception {
        return redisTemplate.delete(key);
    }

    @Override
    public Long delete(Collection<String> keys) throws Exception {
        return redisTemplate.delete(keys);
    }

    @Override
    public Boolean expire(String key, Long expire) throws Exception {
        return redisTemplate.expire(key, expire, DEFAULT_TIME_UNIT);
    }

    @Override
    public <V> void setString(String key, V value) throws Exception {
        redisTemplate.opsForValue().set(key, value);
    }

    @Override
    public <V> void setString(String key, V value, Long expire) throws Exception {
        redisTemplate.opsForValue().set(key, value, expire, DEFAULT_TIME_UNIT);
    }

    @Override
    public <V> Boolean setStringIfAbsent(String key, V value) throws Exception {
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    @Override
    public <V> Boolean setStringIfAbsent(String key, V value, Long expire) throws Exception {
        return redisTemplate.opsForValue().setIfAbsent(key, value, expire, DEFAULT_TIME_UNIT);
    }

    @Override
    public String getString(String key) throws Exception {
        return (String) redisTemplate.opsForValue().get(key);
    }

    @Override
    public <HK, HV> void setHash(String key, Map<HK, HV> map) throws Exception {
        BoundHashOperations<String, HK, HV> ops = redisTemplate.boundHashOps(key);
        ops.putAll(map);
    }

    @Override
    public <HK, HV> Map<HK, HV> getHash(String key) throws Exception {
        BoundHashOperations<String, HK, HV> ops = redisTemplate.boundHashOps(key);
        return ops.entries();
    }

    @Override
    public <V> Long pushToList(String key, boolean pushType, V... values) throws Exception {
        BoundListOperations<String, V> ops = redisTemplate.boundListOps(key);
        Long len = null;
        if(pushType) {
            len = ops.leftPushAll(values);
        }else {
            len = ops.rightPushAll(values);
        }
        return len;
    }

    @Override
    public <V> V popFormList(String key, boolean pushType) throws Exception {
        BoundListOperations<String, V> ops = redisTemplate.boundListOps(key);
        V value = null;
        if(pushType) {
            value = ops.leftPop();
        }else {
            value = ops.rightPop();
        }
        return value;
    }

    @Override
    public <V> void setZSet(String key, Map<V, Double> valMap) throws Exception {
        BoundZSetOperations<String, V> ops = redisTemplate.boundZSetOps(key);
        valMap.forEach((value, score) -> {
            ops.add(value, score);
        });
    }

    @Override
    public <V> Long removeZSet(String key, List<V> list) throws Exception {
        BoundZSetOperations<String, V> ops = redisTemplate.boundZSetOps(key);
        return ops.remove(list);
    }

    @Override
    public <V> Long removeList(String key, List<V> list) throws Exception {
        BoundListOperations<String, V> ops = redisTemplate.boundListOps(key);
        Long len = 0l;
        for(V value : list) {
            Long removeLen = ops.remove(1, value);
            len += removeLen;
        }
        return len;
    }

    @Override
    public String getValueFromHash(String key, String subKey) throws Exception {
        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(key);
        return ops.get(subKey);
    }

    @Override
    public Boolean setValueToHash(String key, String subKey, String value) throws Exception {
        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(key);
        ops.put(subKey, value);
        return true;
    }

    @Override
    public Long delHashField(String key, String subKey) throws Exception {
        BoundHashOperations<String, String, Object> ops = redisTemplate.boundHashOps(key);
        return ops.delete(subKey);
    }

    @Override
    public <V> List<V> getAllFromList(String key) throws Exception {
        BoundListOperations<String, V> ops = redisTemplate.boundListOps(key);
        return ops.range(0, -1);
    }

    @Override
    public <V> Set<V> getAllFromZSet(String key) throws Exception {
        BoundZSetOperations<String, V> ops = redisTemplate.boundZSetOps(key);
        return ops.range(0, -1);
    }

    @Override
    public <V> Set<V> rangeFromList(String key, int start, int end) throws Exception {
        BoundZSetOperations<String, V> ops = redisTemplate.boundZSetOps(key);
        return ops.range(start, end);
    }

    @Override
    public Long llen(String key) throws Exception {
        BoundListOperations ops = redisTemplate.boundListOps(key);
        return ops.size();
    }

    @Override
    public <T> T executeLuaScript(String script, List<String> keys, List<String> args, Class<T> resultType) throws Exception {
        // 定义 RedisScript 对象，指定脚本内容和返回值类型
        DefaultRedisScript<T> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);  // 设置 Lua 脚本内容
        redisScript.setResultType(resultType);  // 设置返回值类型

        // 将 args 转换为数组形式传递给 redisTemplate
        return (T) redisTemplate.execute(redisScript, keys, args.toArray());
    }
}
